Code and explanations from: https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html
import os
import cv2
import matplotlib
import numpy as np
from matplotlib import pyplot as plt
#from google.colab.patches import cv2_imshow
%matplotlib inline
path_original="./office/"
path_resized="./resized/"
resize_divide=4
images_original = [cv2.imread(f"{path_original}{image}", cv2.IMREAD_COLOR) for image in os.listdir(f'{path_original}')]
height, width, _ = images_original[0].shape
height = height // resize_divide
width = width // resize_divide
images = [cv2.resize(image, (width, height)) for image in images_original]
for i, image in enumerate(images):
cv2.imwrite(f"{path_resized}img{i}.png", image)
images = [cv2.imread(f"{path_resized}{image}", cv2.IMREAD_COLOR) for image in os.listdir(f'{path_resized}')]
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,8,0)
objp = np.zeros((7 * 9, 3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:9].T.reshape(-1,2)
print(objp[:6])
print(".......")
print(objp[56:])
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
cv2.findChessboardCorners() : finds pattern in chess board. In my case 7x9 grid. It returns the corner points and retval which will be True if pattern is obtained. These corners will be placed in an order (from left-to-right, top-to-bottom);
cv2.cornerSubPix() : increase corner's accuracy;
cv2.drawChessboardCorners() : draws the pattern;
for img in images:
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (7,9),None)
# If found, add object points, image points (after refining them)
if ret == True:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners2)
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (7,9), corners2,ret)
plt.figure(figsize=(8,16))
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
cv2.calibrateCamera() : returns the camera matrix, distortion coefficients, rotation and translation vectors etc.
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
print("ret : "+str(ret))
print("mtx : "+str(mtx))
print("dist : "+str(dist))
print("rvecs : "+str(rvecs))
print("tvecs : "+str(tvecs))
v2.getOptimalNewCameraMatrix() : refines the camera matrix. If the scaling parameter alpha=0, it returns undistorted image with minimum unwanted pixels. So it may even remove some pixels at image corners. If alpha=1, all pixels are retained with some extra black images. It also returns an image ROI which can be used to crop the result.
for image in images:
first = image.copy()
h, w, _ = image.shape
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
undistorted = cv2.undistort(image, mtx, dist, None, newcameramtx)
plt.figure(figsize=(20, 40))
plt.subplot(121)
plt.title('Original')
plt.imshow(cv2.cvtColor(first, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.subplot(122)
plt.title('Undistorted')
plt.imshow(cv2.cvtColor(undistorted, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()